View Javadoc
1 /* 2 * Title: S/MIME Project 3 * Description: S/MIME email sending capabilities 4 * @Author Vladan Obradovic 5 * @Version 2.0.1 6 */ 7 8 package org.webdocwf.util.smime.smime; 9 10 11 import org.webdocwf.util.smime.exception.SMIMEException; 12 import org.webdocwf.util.smime.exception.ErrorStorage; 13 import org.webdocwf.util.smime.activation.CMSSignedDataSource; 14 import org.webdocwf.util.smime.mail.MultipartGenerator; 15 import org.webdocwf.util.smime.util.ConvertAssist; 16 import org.webdocwf.util.smime.activation.StreamDataSource; 17 import javax.mail.Session; 18 import javax.mail.Message; 19 import javax.mail.Multipart; 20 import javax.mail.Transport; 21 import javax.mail.MessagingException; 22 import javax.mail.internet.HeadersUtil; 23 import javax.mail.internet.MimeMessage; 24 import javax.mail.internet.MimeBodyPart; 25 import javax.mail.internet.MimeMultipart; 26 import javax.mail.internet.InternetAddress; 27 import javax.activation.DataHandler; 28 import javax.activation.FileDataSource; 29 import javax.activation.MimetypesFileTypeMap; 30 import java.util.Vector; 31 import java.util.Properties; 32 import java.util.SimpleTimeZone; 33 import java.util.GregorianCalendar; 34 import java.io.File; 35 import java.io.FileInputStream; 36 import java.io.InputStream; 37 import java.io.ByteArrayInputStream; 38 import java.security.Security; 39 import java.security.KeyStoreException; 40 import java.security.PrivateKey; 41 import java.security.KeyStore; 42 import java.security.cert.X509Certificate; 43 import java.security.cert.CertificateFactory; 44 import java.security.cert.CertificateException; 45 import sun.security.provider.Sun; 46 import org.bouncycastle.jce.provider.BouncyCastleProvider; 47 48 49 /*** 50 * SignedSMIME class is used for creating and sending signed S/MIME message.<BR> 51 * <BR> 52 * Email message is in general composed of the content of the message and of one or 53 * more attachments. The content is visible part of the message, and attacments are 54 * mostly files or other binary data, which are not visible parts of message and 55 * which are used by email as a transport medium. In this implementation content 56 * can be represented in two different forms: <BR> 57 * <BR> 58 * <UL><LI> 59 * text/plain (only text withouth any formating) or 60 * </LI> <LI> 61 * text/html (html coded view of message) 62 * </LI></UL> 63 * Also, content can be absent, but than at least one attachment must be added. 64 * Content can be set on few manners. For text/plain type it can be done in time 65 * of construction with constructor designed special for creation of text/plain 66 * messages. Also, text content can be created by any of setContent() methods, 67 * if construction of object was done by other constructor which create object 68 * with empty content. Construction with other constructor offers a few different 69 * posibilities for importing content data (File, InputStream, String) by using 70 * appropriate setContent() method. If method with four parameters is used, 3rd 71 * ant 4th parameters are not in use for text/plain message and could be set 72 * null. For setting text/html content, construction of object should be done 73 * only by second mentioned constructor, which creates object with empty content. 74 * Content should be populated by html code with setContent() method. 3rd 75 * parameter is used for resolving relative addresses of resources in html 76 * code (images, movies...) and 4th parameter serves as data source for resources 77 * that are on special way addressed in html code. Also, there is a setContent() 78 * method which doesn't care about resources and which creates message content 79 * withouth them. For more information refer to setContent() methods.<BR> 80 * <BR> 81 * Message can contain any number of attachments. Also, message can 82 * be wihouth any attachment, but then content must be present. Every attachment 83 * should be added by performing single addAttachment() method. Attachments 84 * can be added from file or from InputStream. Mime-type which corresponds to 85 * particular attachment is obtained according to extension of file name 86 * (virtual or real file name) passed to addAttachment() method. File mime.types 87 * in META_INF directory contains list of mime-types and corresponding extensions 88 * which are used in determination of mime-type. File can be changed to satisfy 89 * secific requrements. For more information refer to addAttachmenttent() 90 * method.<BR> 91 * <BR> 92 * Message can be external (explicit) or internal (implicit) signed. External 93 * signing allows email receiving clients wihouth implemented SMIME 94 * capabilities to preview the signed SMIME email messages.<BR> 95 * <BR> 96 * Message can be signed with or without Signed Attributes. Signed Attributes 97 * are one optional part of CMS (Cryptographic Message Syntax) signed objects, 98 * and consist of some atributes used in the process of signing (date and time 99 * of signing, capabilities of sending email client, message digest value...). 100 * If those attributes are ommited, only pure message is taken in the process 101 * of signing.<BR> 102 * <BR> 103 * Digest algorithm can be SHA1, MD2 or MD5 which depends on selected signing algorithm.<BR> 104 * <BR> 105 * Capabilities Attributes are one of Signed Attributes, and in the process of 106 * signing (if Signed Attributes are involved) can be set. This attributes 107 * indicate to recipient email client which encipher, symmetric and/or signature 108 * algorithms signer's email client preferes, and they can be used in the next 109 * communication between each others. Setting this posibilities is optional, but 110 * if it is set, order of adding gives the information about most preferes algorithms 111 * within paricular group of algorithms. Defined Capabilities Attributes in this version 112 * of Signed SMIME can be from group: RC2 40, RC2 64, RC2 128, DES and DES_EDE3 for 113 * symmetric encryption algorihms, from group: MD2 with RSA, MD5 with RSA, SHA1 with RSA 114 * and SHA1 with DSA for signing algorithms, and RSA for encipher algorithm. For more 115 * information see setCapabilities method in this class.<BR> 116 * <BR> 117 * Certificates of signers and their root authorities can be included in the 118 * signed message. This posibilities allow the recipient of signed SMIME 119 * message to automatically include signer's certificates as trusted, and verify 120 * signed message. This posibilities are optional.<BR> 121 * <BR> 122 * More than one signer can perform signing of message and they can use 123 * different signing algorithms. Digital signing can be performed by SHA1_WITH_RSA, 124 * MD2_WITH_RSA, MD5_WITH_RSA or SHA1_WITH_DSA.<BR> 125 * <BR> 126 */ 127 public class SignedSMIME { 128 129 /*** 130 * Container for MIME message 131 */ 132 private MimeMessage message; 133 134 /*** 135 * Storage for .pfx files corresponding to appropriate signing session (used 136 * for first type of addSigner function). 137 */ 138 private Vector ksArray = new Vector(0, 1); 139 140 /*** 141 * Storage for digest algorithm corresponding to appropriate signing session 142 * (used for first type of addSigner function). 143 */ 144 private Vector digestArray = new Vector(0, 1); 145 146 /*** 147 * Storage for byte[2] grouped indicators (used for first type of addSigner 148 * function). 149 */ 150 private Vector including = new Vector(0, 1); 151 152 /*** 153 * Storage for certificate chain corresponding to appropriate signing session 154 * (used for second type of addSigner function) 155 */ 156 private Vector certChainArray = new Vector(0, 1); 157 158 /*** 159 * Storage for private key corresponding to appropriate signing session (used 160 * for second type of addSigner function) 161 */ 162 private Vector privKeyArray = new Vector(0, 1); 163 164 /*** 165 * Storage for digest algorithm corresponding to appropriate signing session 166 * (used for second type of addSigner function) 167 */ 168 private Vector digestArray2 = new Vector(0, 1); 169 170 /*** 171 * Storage for byte[2] grouped indicators (used for second type of addSigner 172 * function) 173 */ 174 private Vector including2 = new Vector(0, 1); 175 176 /*** 177 * Storage for MIME bodyparts 178 */ 179 private Vector bodyPartArray = new Vector(0, 1); 180 181 /*** 182 * Storage for additional certificates 183 */ 184 private Vector aditionalCerts = new Vector(0, 1); 185 186 /*** 187 * Temporary storage for capabilities (after method addSigner, this object is 188 * copied to capabilities or capabilities2) 189 */ 190 private Vector capabilitiesTemp = new Vector(0, 1); 191 192 /*** 193 * Storage for capabilities (used for first type of addSigner function) 194 */ 195 private Vector capabilities = new Vector(0, 1); 196 197 /*** 198 * Storage for capabilities (used for second type of addSigner function) 199 */ 200 private Vector capabilities2 = new Vector(0, 1); 201 202 /*** 203 * Indication that at least one recipient must be TO (others may be CC or BCC) 204 */ 205 private boolean indicatorTo = false; 206 207 /*** 208 * Indicator of the presence of plain text content 209 */ 210 private boolean textContentPresence = false; 211 212 /*** 213 * Initializes the JavaMail session for SMTP and MimeMessage for signing. 214 * Dynamically loads the BC and SUN provider necessary for encryption. This 215 * constructor is used for creating message with text/plain content. For creating 216 * html formated content (text/html) other constructor should be used in 217 * combination with one of the setContent methods. Note that after using this 218 * constructor setContent method can be used only if "content" argument of 219 * constructor was given as null, otherwise setContent method can't be used 220 * because content is already set as text/plain. 221 * @param smtpHost name of SMTP host used for sending email 222 * @param fromAddress email address of sender (FROM field in email header) 223 * @param subject subject of email (SUBJECT field in email header) 224 * @param content text/plain content of email message 225 * @exception SMIMEException if smtpHost or fromAddress parameters are null. 226 * Also, it can be caused by non SMIMEException which is MessagingException. 227 */ 228 public SignedSMIME(String smtpHost, String fromAddress, String subject, 229 String content) throws SMIMEException { 230 try { 231 Security.addProvider(new BouncyCastleProvider()); // Dynamic loading the BC provider 232 Security.addProvider(new Sun()); // Dynamic loading the SUN provider necessary for SHA1withRSA 233 234 if (smtpHost == null | fromAddress == null) 235 throw new SMIMEException(this, 1041); 236 Properties sesProp = new Properties(); 237 238 sesProp.setProperty("mail.smtp.host", smtpHost); 239 Session ses = Session.getInstance(sesProp); 240 241 message = new MimeMessage(ses); 242 InternetAddress from = new InternetAddress(fromAddress); 243 244 message.setFrom(from); 245 if (subject != null) 246 message.setSubject(subject); 247 if (content != null) { 248 MimeBodyPart mbp = new MimeBodyPart(); 249 250 mbp.setText(content); 251 bodyPartArray.addElement(mbp); 252 textContentPresence = true; 253 } 254 } catch (Exception e) { 255 throw SMIMEException.getInstance(this, e, "constructor"); 256 } 257 } 258 259 /*** 260 * Initializes the JavaMail session for SMTP and MimeMessage for signing. 261 * Dynamically loads the BC and SUN provider necessary for encryption. This 262 * constructor does not create content of message and it can be set later with 263 * one of setContent methods. Also, message can be left withouth content, but 264 * then at least one attachement must be added. 265 * @param smtpHost name of SMTP host used for sending email 266 * @param fromAddress email address of sender (FROM field in email header) 267 * @param subject subject of email (SUBJECT field in email header) 268 * @exception SMIMEException if smtpHost or fromAddress parameters are null. 269 * Also, it can be caused by non SMIMEException which is MessagingException. 270 */ 271 public SignedSMIME(String smtpHost, String fromAddress, String subject) 272 throws SMIMEException { 273 this(smtpHost, fromAddress, subject, null); 274 } 275 276 /*** 277 * Sets message content. Message content can be given in two differrent forms: 278 * text and html code. If content is type of text, parameter "type" should be 279 * "text/plain" and other two parameters are not in use (should be set null). 280 * If content is type of html code, parameter "type" should be set as "text/html", 281 * otherwise (if it is set as "text/plain") html code is processed as a plain 282 * text. This method can be performed only once.<BR> 283 * <BR> 284 * In case of html content, it is essential to (on appropriate way) associate some 285 * attributes of particular elements in html code ("background" or "src" atributes) 286 * with corresponding ressources (URL-s, relative file addresses or byte array 287 * streams). This resources should all be sent with message to enable recipient 288 * to see complete html message. Location of resources can be given in few 289 * different forms and depending on that, allocation resolving can be successful or 290 * not. Following text represents different possibilities for defining locations 291 * of resources (pictures, animations, sound...) inside of html code passed to 292 * this method, and necessery passed additional parameters used for resolving 293 * this resource locations.<BR> 294 * <BR> 295 * <UL> 296 * <LI>URL defined as: http://... is left unchanged. This resource is not sent 297 * with the message and it couldn't be seen by recipient if it is not online on 298 * the internet.</LI> 299 * <LI>URL defined as: file://... is transformed to corresponding Content ID if 300 * the resource can be found on specified location and it is sent with message.</LI> 301 * <LI>Absolute path, for example defined as: "c:\tmp\test\picture.bmp", is 302 * transformed to corresponding Content ID if the resource can be found on 303 * specified location, and is sent with message. If all resources in html 304 * code are specified with its absolute path, the 3rd parameter in this method 305 * can be null.</LI> 306 * <LI>Relative path of all resources specified in html code, for example 307 * defined as: ".\test\picture.bmp" and ".\example\flush.swf", must be defined 308 * to be relative to same directory path (in this case it is c:\tmp). This parameter 309 * (common directory path) is given as 3rd parameter in this method, and is named 310 * "path". If html code is obtained from .html file, necessery common directory 311 * path is usually path to this .html file. Location of resource is transformed 312 * to corresponding Content ID if the resource can be found on specified location. 313 * This location is sent with the message.</LI> 314 * <LI>Byte array stream as resource for html attribute must be referenced from 315 * html code as: <BR> 316 * <BR><PRE> 317 * *****nnn<virtual_file_name><BR> 318 * <BR></PRE> 319 * Five '*' characters (must be five) define that it is resource expected from 320 * the stream. Other three characters must be digits (000-999) and represent 321 * index of corresponding stream in stream array. virtual_file_name is name and 322 * extension assigned to data passed from stream. Name is used in construction of 323 * "name" parameter in Content-Type, while extension of file name is used in 324 * detection of appropriate mime-type. Lenght of virtual_file_name is not 325 * important. If there is no data referenced from byte array stream ,4th 326 * parameter of this method named "resources" can be null. Also, if all resources 327 * are passed through the array of streams, 3th parameter ("path") can be null. 328 * Location of resource is transformed to corresponding Content ID if no error 329 * has occured during the process of allocation.</LI> 330 * </UL> 331 * <BR> 332 * All mentioned resource allocation types can be combined together in the same 333 * html code, and all will be processed with appropriate use of this method.<BR> 334 * <BR> 335 * Note that number of resource references that are defined in html code by 336 * using virtual_file_names must be greater than or equal to number of elements 337 * in array of InputStream (4th parameter). If one resource (one element in array 338 * of IputStream) is used in html code more than once, it is advisable to use 339 * same virtual_file_name in html code because message is then sent with only 340 * one attached resource (image, movie...). It is essetntial that desired resource 341 * in input stream array corresponds to specified "nnn" part of virtual_file_name.<BR> 342 * <BR> 343 * If resources specified on any described name can not be found or resolved, 344 * or if any exception has occured during its processing, they won't be added and 345 * html message will be sent withouth them. 346 * @param content String representation of message content (text or html code). 347 * @param type type of given content. It can take values: "text/plain" or 348 * "text/html". 349 * @param path common directory path for relative file locations in html code. 350 * It can be null if all resources set absolute path or are defined by 351 * byte array streams, or if sending resources with relative address it is not desired. 352 * Also, it is set to null in case of text/plain message. 353 * @param resources way for representing resources used in the given html code 354 * which will be added to message as array of InputStream. Detail use 355 * of this argument is described above. It can be null if no resources as byte 356 * array stream are used, or if sending resources given in that way is not desired. 357 * Also, it is set to null in case of text/plain message. 358 * @exception SMIMEException if content is tried to be added twice, or in case of 359 * wrong "type" parameter. Also, it can be caused by non SMIMEException which can 360 * be one of the following: MessagingException UnsoportedEncodingException. 361 */ 362 public void setContent(String content, String type, String path, 363 InputStream[] resources) throws SMIMEException { 364 365 if (content != null) { 366 ByteArrayInputStream bais = null; 367 368 try { 369 bais = new ByteArrayInputStream(content.getBytes("ISO-8859-1")); 370 } catch (Exception e) { 371 throw SMIMEException.getInstance(this, e, "setContent"); 372 } 373 this.setContent(bais, type, path, resources); 374 375 } else 376 throw new SMIMEException(this, 1035); 377 } 378 379 /*** 380 * Sets message content from InputStream. This method can be performed only once. 381 * Message content can be given in two differrent forms: text and html code. If 382 * content is type of text, parameter "type" should be "text/plain", while if 383 * content is type of html code, parameter "type" should be set as "html/code". 384 * For further information refer to setContent method with four arguments 385 * (String, String, String, InputStream[] ) which is called by this method. 386 * @param content message content data given from any InputStream. 387 * Data can be text or html code and will be interpreted according to second 388 * parameter: "type". 389 * @param type type of given content. It can take values: "text/plain" or 390 * "text/html". 391 * @param path common directory path for relative file locations in html code. 392 * It can be null if all resources in html code have set absolute path or are 393 * defined by byte array streams, or if sending resources with relative address 394 * is not desired. Also, it is set to null in case of text/plain message. 395 * @param resources way for representing resources used in the given html code 396 * which will be added to message as array of InputStreams. Detail use 397 * of this argument is described in other setContent methods mentioned before. 398 * It can be null if no resources as byte array stream are used, or if sending 399 * resources given in that way is not desired. Also, it is set to null in case 400 * of text/plain message. 401 * @exception SMIMEException if content is tried to be added twice , in case of 402 * wrong "type" parameter or in case when parameter content is null. Also, it can 403 * be caused by non SMIMEException which is MessagingException. 404 */ 405 public void setContent(InputStream content, String type, String path, 406 InputStream[] resources) throws SMIMEException { 407 if (textContentPresence) 408 throw new SMIMEException(this, 1049); 409 if (content != null) { 410 try { 411 if (type.equalsIgnoreCase("text/plain")) { 412 MimeBodyPart mbp = new MimeBodyPart(); 413 String temp = new String(ConvertAssist.inStreamToByteArray(content), "ISO-8859-1"); 414 415 mbp.setText(temp, "ISO-8859-1"); 416 bodyPartArray.add(0, mbp); 417 textContentPresence = true; 418 } else if (type.equalsIgnoreCase("text/html")) { 419 MimeMultipart htmlMultipart = 420 MultipartGenerator.getHtmlMultipart(content, path, resources); 421 422 bodyPartArray.add(0, htmlMultipart); 423 textContentPresence = true; 424 } else 425 throw new SMIMEException(this, 1048); 426 } catch (Exception e) { 427 throw SMIMEException.getInstance(this, e, "setContent"); 428 } 429 } else 430 throw new SMIMEException(this, 1035); 431 } 432 433 /*** 434 * Sets message content from InputStream. This method can be performed only once. 435 * Message content can be given in two differrent forms: text and html code. If 436 * content is type of text, parameter "type" should be "text/plain", while if 437 * content is type of html code, parameter "type" should be set as "html/code". 438 * If html code content is set by this method, message will be generated withouth 439 * inclusion of the resources defined in paricular html element's attribute ("src" and 440 * "background"). Only plain html code will be sent and any reference to local 441 * file system resources will be useless for recipient of the message. HTTP referenced 442 * resources can still be available if recipient is online on Internet. Message 443 * generated on this way is smaller so encrypting process should be faster. 444 * @param content message content data given from any InputStream. 445 * Data could be text or html code and will be interpreted according to second 446 * parameter: "type". 447 * @param type type of given content. It can take values: "text/plain" or 448 * "text/html". 449 * @exception SMIMEException if content is tried to be added twice , in case of 450 * wrong "type" parameter or in case when parameter content is null. Also, it can 451 * be caused by non SMIMEException which is MessagingException. 452 */ 453 public void setContent(InputStream content, String type) throws SMIMEException { 454 if (textContentPresence) 455 throw new SMIMEException(this, 1049); 456 if (content != null) { 457 try { 458 if (type.equalsIgnoreCase("text/plain")) { 459 MimeBodyPart mbp = new MimeBodyPart(); 460 String temp = new String(ConvertAssist.inStreamToByteArray(content), "ISO-8859-1"); 461 462 mbp.setText(temp, "ISO-8859-1"); 463 bodyPartArray.add(0, mbp); 464 textContentPresence = true; 465 } else if (type.equalsIgnoreCase("text/html")) { 466 MimeMultipart htmlMultipart = 467 MultipartGenerator.getHtmlMultipart(content); 468 469 bodyPartArray.add(0, htmlMultipart); 470 textContentPresence = true; 471 } else 472 throw new SMIMEException(this, 1048); 473 } catch (Exception e) { 474 throw SMIMEException.getInstance(this, e, "setContent"); 475 } 476 } else 477 throw new SMIMEException(this, 1035); 478 } 479 480 /*** 481 * Sets message content from String. This method can be performed only once. 482 * Message content can be given in two differrent forms: text and html code. If 483 * content is type of text, parameter "type" should be "text/plain", while if 484 * content is type of html code, parameter "type" should be set as "html/code". 485 * If html code content is set by this method, message will be generated withouth 486 * inclusion of the resources defined in paricular html element's attribute ("src" or 487 * "background"). Only plain html code will be sent and any reference to local 488 * file system resources will be useless for recipient of the message. HTTP referenced 489 * resources can still be available if recipient is online on Internet. Message 490 * generated on this way is smaller, so encrypting process should be faster. 491 * @param content message content data given as String which can 492 * be text or html code and will be interpreted according to second parameter: 493 * "type". 494 * @param type type of given content. It can take values: "text/plain" or 495 * "text/html". 496 * @exception SMIMEException if content is tried to be added twice, or in case of 497 * wrong "type" parameter. Also, it can be caused by non SMIMEException which can 498 * be one of the following: MessagingException UnsoportedEncodingException. 499 */ 500 public void setContent(String content, String type) throws SMIMEException { 501 502 if (content != null) { 503 ByteArrayInputStream bais = null; 504 505 try { 506 bais = new ByteArrayInputStream(content.getBytes("ISO-8859-1")); 507 } catch (Exception e) { 508 throw SMIMEException.getInstance(this, e, "setContent"); 509 } 510 this.setContent(bais, type); 511 512 } else 513 throw new SMIMEException(this, 1035); 514 } 515 516 /*** 517 * Sets message content from file represented by File object. This method can be 518 * performed only once. Message content can be given in two differrent forms: 519 * text and html code. If content is type of text, parameter "type" should be 520 * "text/plain", while if content is type of html code, parameter "type" should 521 * be set as "html/code". For further information refer to setContent method 522 * with four arguments (String, String, String, InputStream[] ) which is called 523 * by this method. 524 * @param inFile location of file which is used for content of the message 525 * @param type type of given content. It can take values: "text/plain" or 526 * "text/html". 527 * @exception SMIMEException if content is tried to be added twice, in case of 528 * wrong "type" parameter, or if passed file (as File object) does not exist in 529 * file sistem. Also, it can be caused by non SMIMEException which can be one of 530 * the following: MessagingException or IOException. 531 */ 532 public void setContent(File inFile, String type) throws SMIMEException { 533 534 if (textContentPresence) 535 throw new SMIMEException(this, 1049); 536 if (inFile != null && inFile.exists()) { 537 try { 538 File inFileAbs = inFile.getAbsoluteFile().getCanonicalFile(); 539 String content = ConvertAssist.readFileToString(inFileAbs); 540 541 this.setContent(content, type, inFile.getParent(), null); 542 } catch (Exception e) { 543 throw SMIMEException.getInstance(this, e, "setContent"); 544 } 545 } else 546 throw new SMIMEException(this, 1034); 547 } 548 549 /*** 550 * Sets REPLY TO field in message header 551 * @param replyAddress email address used for reply 552 * @exception SMIMEException caused by non SMIMEException which is 553 * MessagingException. Also javax.mail.internet.AddressException is thrown 554 * from instances of InternetAddress class (but AddressException extends 555 * MessagingException). 556 */ 557 public void setReply(String replyAddress) throws SMIMEException { 558 try { 559 InternetAddress reply[] = new InternetAddress[1]; 560 561 reply[0] = new InternetAddress(replyAddress); 562 message.setReplyTo(reply); 563 } catch (Exception e) { 564 throw SMIMEException.getInstance(this, e, "addRecipient"); 565 } 566 } 567 568 /*** 569 * Adds recipient address, type and .cer file of email recipient. 570 * @param recipientAddress email address of recipent (fields TO or CC or BCC 571 * in email message header) 572 * @param type should be TO, CC or BCC. 573 * @exception SMIMEException if type of addressing of the messages is not TO, CC, 574 * or BCC. 575 * @exception SMIMEException caused by non SMIMEException which is 576 * MessagingException. 577 */ 578 public void addRecipient(String recipientAddress, String type) throws SMIMEException { 579 try { 580 if (!type.equalsIgnoreCase("TO") & !type.equalsIgnoreCase("BCC") & !type.equalsIgnoreCase("CC")) 581 throw new SMIMEException(this, 1042); 582 if (type.equalsIgnoreCase("TO")) { 583 message.addRecipients(Message.RecipientType.TO, recipientAddress); 584 indicatorTo = true; 585 } else if (type.equalsIgnoreCase("CC")) 586 message.addRecipients(Message.RecipientType.CC, recipientAddress); 587 else if (type.equalsIgnoreCase("BCC")) 588 message.addRecipients(Message.RecipientType.BCC, recipientAddress); 589 } catch (Exception e) { 590 throw SMIMEException.getInstance(this, e, "addRecipient"); 591 } 592 593 } 594 595 /*** 596 * Adds file as attachment to email message 597 * @param fileName path and file name used for attachment 598 * @exception SMIMEException if passed file (as File object) does not exist in 599 * file sistem. Also, it can be caused by non SMIMEException which is 600 * MessagingException 601 */ 602 public void addAttachment(String fileName) throws SMIMEException { 603 File fn = new File(fileName); 604 605 this.addAttachment(fn); 606 } 607 608 /*** 609 * Adds file as attachment to email message 610 * @param file used for attachment represented as File object 611 * @exception SMIMEException if passed file (as File object) does not exist in 612 * file sistem. Also, it can be caused by non SMIMEException which is 613 * MessagingException 614 */ 615 public void addAttachment(File file) throws SMIMEException { 616 if (!file.exists()) 617 throw new SMIMEException(this, 1034); 618 MimeBodyPart attachment = new MimeBodyPart(); 619 FileDataSource fd = new FileDataSource(file); 620 621 try { 622 attachment.setDataHandler(new DataHandler(fd)); 623 attachment.setDisposition(attachment.ATTACHMENT); 624 attachment.setFileName(file.getName()); 625 } catch (Exception e) { 626 throw SMIMEException.getInstance(this, e, "addAttachment"); 627 } 628 629 bodyPartArray.addElement(attachment); 630 } 631 632 /*** 633 * Adds data from InputStream as attachment to email message 634 * @param data byte array from InputStream 635 * @param fileName virtual or real file name (wihouth path). Correct information 636 * about name; extension of file name is especially important. Name 637 * is used in construction of "name" parameter in Content-Type header line of 638 * body parts of mime message. Extension of file is used in detection of 639 * appropriate mime-type. 640 * @exception SMIMEException caused by non SMIMEException which is 641 * MessagingException 642 */ 643 public void addAttachment(InputStream data, String fileName) throws SMIMEException { 644 MimeBodyPart attachment = new MimeBodyPart(); 645 646 try { 647 attachment.setDataHandler(new DataHandler(new StreamDataSource(data, fileName))); 648 attachment.setDisposition(attachment.ATTACHMENT); 649 attachment.setFileName(fileName); 650 bodyPartArray.addElement(attachment); 651 } catch (Exception e) { 652 throw SMIMEException.getInstance(this, e, "addAttachment"); 653 } 654 } 655 656 /*** 657 * Sets Capabilities Attributes (method is optional, but if exists, must be 658 * performed before addSigner method). Depending on parameter type0, other five 659 * parameters make order in specific group of algorithms. Groups of algorithms 660 * with positions of specific algorithms are:<BR> 661 * (SIGNATURE, MD2 with RSA, MD5 with RSA, SHA1 with RSA, SHA1 with DSA, Unused field)<BR> 662 * (SYMMETRIC, RC2 40 bits, RC2 64 bits, RC2 128 bits, DES, DES_EDE3)<BR> 663 * (ENCIPHER, RSA, Unused field, Unused field, Unused field, Unused field)<BR> 664 * <BR> 665 * For example, if we wish to set Capabilities Attributes for symmetric algorithms 666 * in order: RC2 64 bits, RC2 40 bits and DES, encipher algorithm RSA (only possible 667 * in this version), and signature algorithms in order: SHA1 with RSA, MD5 with RSA 668 * and MD2 with RSA, we should make following lines of code<BR> 669 * <BR> 670 * setCapabilities ("SYMMETRIC", 2, 1, 0, 3, 0)<BR> 671 * setCapabilities ("ENCIPHER", 1, 0, 0, 0, 0)<BR> 672 * setCapabilities ("SIGNATURE", 3, 2, 1, 0, 0)<BR> 673 * <BR> 674 * 0 means exclusion of algorithm from the specified position in the method. It is 675 * free to decide which algorithm will be included, or which group of algorithm 676 * will be included in Capabilities Attributes. If no groups are added, capabilities 677 * attributes won't be added to Signed Attributes. If two or more signers will 678 * sign the message, and their capabilities are different, this method should 679 * be performed before every signing if we wish to specify Capabilities 680 * Attributes for all particular signers. If type0 parameter is set as:<BR> 681 * setCapabilities ("DEFAULT", 0, 0, 0, 0, 0)<BR> 682 * it is equivalent to:<BR> 683 * setCapabilities ("SYMMETRIC", 1, 0, 0, 0, 0)<BR> 684 * setCapabilities ("ENCIPHER", 0, 0, 1, 0, 0)<BR> 685 * setCapabilities ("SIGNATURE", 1, 0, 0, 0, 0)<BR> 686 * @param type0 sets group of algorithms for capabilities attributes. It can be set 687 * with values: SIGNATURE, SYMMETRIC, ENCIPHER or DEFAULT. 688 * @param par10 sets order in group of parameters, or exclude some algorithms 689 * from capabilities atributes. Can take values 1, 2, 3, 4 or 5 and 0 for 690 * exclusion of the particular algorithm. 691 * @param par20 same as for par10 692 * @param par30 same as for par10 693 * @param par40 same as for par10 694 * @param par50 same as for par10 695 * @exception SMIMEException if method is performed more than three times for one signer, 696 * or in case of wrong values of parameters. 697 */ 698 public void setCapabilities(String type0, int par10, int par20, int par30, 699 int par40, int par50) throws SMIMEException { 700 int[] tempType = { par10, par20, par30, par40, par50 }; 701 702 capabilitiesTemp.addElement(type0); 703 capabilitiesTemp.addElement(tempType); 704 if (capabilitiesTemp.size() > 6) 705 throw new SMIMEException(this, 1045); 706 } 707 708 /*** 709 * Adds signer to signed S/MIME message 710 * @param pfxfileName path and file name with certificate and private key 711 * corresponding to the sender of the message (file with .p12 or .pfx extension) 712 * @param password used to access to .pfx or .p12 file 713 * @param signingAlg algorithm used for signing (can be SHA1_WITH_RSA, 714 * MD2_WITH_RSA, MD5_WITH_RSA or SHA1_WITH_DSA). 715 * @param includingCert including/not including certificates to signed 716 * message 717 * @param includingSignAttrib including/not including signed attributes 718 * to signed message. Must be set to true in case of implicit signing 719 * @exception SMIMEException caused by non SMIMEException which can be one of the 720 * following: FileNotFoundException, NoSuchProviderException, KeyStoreException 721 * CertificateException, NoSuchAlgorithmException or IOException. 722 */ 723 public void addSigner(String pfxfileName, String password, String signingAlg, 724 boolean includingCert, boolean includingSignAttrib) throws SMIMEException { 725 try { 726 char[] paswCh = password.toCharArray(); 727 FileInputStream inPFX = new FileInputStream(pfxfileName); 728 KeyStore ks = KeyStore.getInstance("PKCS12", "BC"); 729 730 ks.load(inPFX, paswCh); 731 inPFX.close(); 732 boolean[] incl = { includingCert, includingSignAttrib }; 733 734 ksArray.addElement(ks); 735 digestArray.addElement(signingAlg); 736 including.addElement(incl); 737 if (capabilitiesTemp.size() != 0) { 738 for (int i = 0; i != capabilitiesTemp.size(); i++) 739 capabilities.addElement(capabilitiesTemp.elementAt(i)); 740 } 741 for (int i = 0; i != (6 - capabilitiesTemp.size()); i++) 742 capabilities.addElement(null); 743 capabilitiesTemp = new Vector(0, 1); 744 } catch (Exception e) { 745 throw SMIMEException.getInstance(this, e, "addSigner"); 746 } 747 } 748 749 /*** 750 * Adds signer to signed S/MIME message 751 * @param chain certificate chain. First certificate in array must be 752 * owner's certificate, and last certificate has to be root certificate 753 * @param privKey private key corresponding to owner's certificate (DSA 754 * or RSA depend on type of signing) 755 * @param signingAlg algorithm used for signing (can be SHA1_WITH_RSA, 756 * MD2_WITH_RSA, MD5_WITH_RSA or SHA1_WITH_DSA). 757 * @param includingCert including/not including certificates to signed 758 * message 759 * @param includingSignAttrib including/not including signed attributes 760 * to signed message. Must be set to true in case implicit signing 761 */ 762 public void addSigner(X509Certificate[] chain, PrivateKey privKey, 763 String signingAlg, boolean includingCert, boolean includingSignAttrib) { 764 boolean[] incl = { includingCert, includingSignAttrib }; 765 766 certChainArray.addElement(chain); 767 privKeyArray.addElement(privKey); 768 digestArray2.addElement(signingAlg); 769 including2.addElement(incl); 770 if (capabilitiesTemp.size() != 0) { 771 for (int i = 0; i != capabilitiesTemp.size(); i++) 772 capabilities2.addElement(capabilitiesTemp.elementAt(i)); 773 } 774 for (int i = 0; i != (6 - capabilitiesTemp.size()); i++) 775 capabilities2.addElement(null); 776 capabilitiesTemp = new Vector(0, 1); 777 } 778 779 /*** 780 * Adds additional certificate to signed message. 781 * @param cert X509 certificate. 782 */ 783 public void addCertificate(X509Certificate cert) { 784 aditionalCerts.addElement(cert); 785 } 786 787 /*** 788 * Creates and signes the message with default implicit signing. 789 * @exception SMIMEException if one of recipients is not declared as TO 790 * recipient, or if there is no message for signing. Also, it can be caused 791 * by non SMIMEException which can be one of the following: MessagingException 792 * or IOException. 793 */ 794 public void signing() throws SMIMEException { 795 this.signing(false); 796 } 797 798 /*** 799 * Creates and signes the message 800 * @param externalSignature choice between implicit and explicit signing 801 * (true = explicit or external signing, false = implicit or internal signing). 802 * @exception SMIMEException if one of recipients is not declared as TO 803 * recipient, or if there is no message for signing. Also, it can be caused 804 * by non SMIMEException which can be one of the following: MessagingException, 805 * or IOException. 806 */ 807 public void signing(boolean externalSignature) throws SMIMEException { 808 try { 809 if (indicatorTo != true) 810 throw new SMIMEException(this, 1043); 811 if (textContentPresence & bodyPartArray.size() == 1) { // message contains only content 812 if (bodyPartArray.elementAt(0) instanceof MimeBodyPart) { // text/plain message 813 MimeBodyPart contentBody = (MimeBodyPart) bodyPartArray.elementAt(0); 814 815 message.setContent((String) contentBody.getContent(), contentBody.getContentType()); 816 message.setDisposition(message.INLINE); 817 } else // text/html message 818 message.setContent((MimeMultipart) bodyPartArray.elementAt(0)); 819 } else if (bodyPartArray.size() != 0) { 820 Multipart mp = new MimeMultipart(); 821 822 for (int i = 0; i != bodyPartArray.size(); i++) { 823 if (bodyPartArray.elementAt(i) instanceof MimeMultipart) { 824 MimeBodyPart forMulti = new MimeBodyPart(); 825 826 forMulti.setContent((MimeMultipart) bodyPartArray.elementAt(i)); 827 mp.addBodyPart(forMulti); 828 } else 829 mp.addBodyPart((MimeBodyPart) bodyPartArray.elementAt(i)); 830 } 831 message.setContent(mp); 832 } else 833 throw new SMIMEException(this, 1044); 834 835 CMSSignedDataSource ss = new CMSSignedDataSource(message, externalSignature); 836 837 for (int i = 0; i < ksArray.size(); i++) { 838 boolean[] incl = (boolean[]) including.elementAt(i); 839 840 for (int j = 6 * i; j != (6 * (i + 1)) && capabilities.elementAt(j) != null; j = j + 2) { 841 int[] capabil = (int[]) capabilities.elementAt(j + 1); 842 843 ss.setCapabilities((String) capabilities.elementAt(j), capabil[0], capabil[1], capabil[2], capabil[3], capabil[4]); 844 } 845 ss.addSigner((KeyStore) ksArray.elementAt(i), incl[0], incl[1], (String) digestArray.elementAt(i)); 846 } 847 for (int i = 0; i < certChainArray.size(); i++) { 848 boolean[] incl2 = (boolean[]) including2.elementAt(i); 849 850 for (int j = 6 * i; j != (6 * (i + 1)) && capabilities2.elementAt(j) != null; j = j + 2) { 851 int[] capabil = (int[]) capabilities2.elementAt(j + 1); 852 853 ss.setCapabilities((String) capabilities2.elementAt(j), capabil[0], capabil[1], capabil[2], capabil[3], capabil[4]); 854 } 855 ss.addSigner((X509Certificate[]) certChainArray.elementAt(i), (PrivateKey) privKeyArray.elementAt(i), incl2[0], incl2[1], (String) digestArray2.elementAt(i)); 856 } 857 for (int i = 0; i < aditionalCerts.size(); i++) { 858 ss.addCertificate((X509Certificate) aditionalCerts.elementAt(i)); 859 } 860 message.setDataHandler(new DataHandler(ss)); 861 HeadersUtil.updateHeaders(message); 862 message.setDescription("Signed SMIME message."); 863 message.setDisposition(message.ATTACHMENT); 864 SimpleTimeZone tz = (SimpleTimeZone) SimpleTimeZone.getDefault(); // Sets date and time 865 GregorianCalendar cal = new GregorianCalendar(tz); 866 867 message.setSentDate(cal.getTime()); 868 869 clean(); 870 } catch (Exception e) { 871 throw SMIMEException.getInstance(this, e, "signing"); 872 } 873 874 } 875 876 /*** 877 * Returns SMIME Message 878 * @return Signed S/MIME message 879 */ 880 public MimeMessage getSignedMessage() { 881 return message; 882 } 883 884 /*** 885 * Sends S/MIME message to SMTP host 886 * @exception MessagingException caused by use of methods from objects of class 887 * Transport. 888 */ 889 public void send() throws MessagingException { 890 Transport.send(message); 891 } 892 893 /*** 894 * Releases unnecessary memory 895 */ 896 private void clean() { 897 ksArray = null; 898 digestArray = null; 899 including = null; 900 certChainArray = null; 901 privKeyArray = null; 902 digestArray2 = null; 903 including2 = null; 904 bodyPartArray = null; 905 aditionalCerts = null; 906 capabilitiesTemp = null; 907 capabilities = null; 908 capabilities2 = null; 909 System.gc(); // Calling garbage collector 910 } 911 } 912

This page was automatically generated by Maven